﻿using System;
using System.Collections.Generic;
using System.Linq;
using LeakView.common;
using log4net;

namespace LeakView.service
{

    public class MainLeakPair : AjaxValue<AjaxLeakPair>
    {
        public MainLeakPair()
        {
        }

        protected override void OnFetchFinish()
        {
            base.OnFetchFinish();
        }

        protected override void OnFetchPrepare()
        {
            var pairId = AnyConfigs.get("APP").get("PairId").GetOrDefault("default");
            var url = AnyConfigs.get("APP").get("MainURL").GetOrDefault("http://localhost:8080");

            this.Content
                .setUrl(url, "client/pair.do")
                .clearParameters()
                .AddParameter("id", pairId);

            base.OnFetchPrepare();
        }
    }


    public class MainStatus : AjaxValue<AjaxLeakPairStatus>
    {
        protected override void OnFetchFinish()
        {
            base.OnFetchFinish();
        }

        protected override void OnFetchPrepare()
        {
            var pairId = AnyConfigs.get("APP").get("PairId").GetOrDefault("default");
            var url = AnyConfigs.get("APP").get("MainURL").GetOrDefault("http://localhost:8080");

            this.Content
                .setUrl(url, "client/status.do")
                .clearParameters()
                .AddParameter("pairId", pairId);

            base.OnFetchPrepare();
        }
    }

    public class MainCurrent : AjaxValue<List<AjaxLeakInfo>>
    {
        readonly Dictionary<long, AjaxLeakInfo> leaks = new Dictionary<long, AjaxLeakInfo>();
        readonly List<long> confirmed = new List<long>();
        readonly List<long> added = new List<long>();

        public event Action<AjaxLeakInfo> LeakCreatedHandler;
        public event Action<AjaxLeakInfo> LeakDeletedHandler;


        protected override void OnFetchFinish()
        {

            // 删除主控上已经没有的Leak信息
            var ids = this.leaks.Keys.ToList();
            Value.Value?.ForEach((leak) =>
            {
                ids.Remove(leak.id);
            });

            ids.ForEach(id =>
            {
                var leak = leaks[id];
                leaks.Remove(id);
                LeakDeletedHandler?.Invoke(leak);
            });

            // 加入新的报警列表，已经存在的将在InsertLeak中忽略
            Value.Value?.ForEach((leak) =>
            {
                InsertLeak(leak);
            });

            base.OnFetchFinish();
        }

        protected override void OnFetchPrepare()
        {
            var pairId = AnyConfigs.get("APP").get("PairId").GetOrDefault("default");
            var url = AnyConfigs.get("APP").get("MainURL").GetOrDefault("http://localhost:8080");

            this.Content
                .setUrl(url, "client/current.do")
                .clearParameters()
                .AddParameter("pairId", pairId);

            base.OnFetchPrepare();
        }

        public bool Leaking
        {
            get { return leaks.Count > 0; }
        }

        public void ConfirmLeak(AjaxLeakInfo leak)
        {
            if (leaks.ContainsKey(leak.id))
            {
                AjaxLeakInfo ajaxLeakInfo = leaks[leak.id];

                leaks.Remove(ajaxLeakInfo.id);
                LeakDeletedHandler?.Invoke(ajaxLeakInfo);
            }
        }

        public List<AjaxLeakInfo> GetCurrentLeaks()
        {
            return leaks.Values.ToList();
        }

        public void AddConfirmed(AjaxLeakInfo leak)
        {
            confirmed.Add(leak.id);
        }

        private void RemoveConfirmed()
        {
            confirmed.ForEach((id) =>
            {
                if (leaks.ContainsKey(id))
                {
                    leaks.Remove(id);
                    LeakDeletedHandler?.Invoke(leaks[id]);
                }
            });
            confirmed.Clear();
        }

        private void InsertLeak(AjaxLeakInfo leak)
        {
            if (added.Contains(leak.id))
                return;

            if (this.leaks.ContainsKey(leak.id))
                return;

            this.leaks.Add(leak.id, leak);

            LeakCreatedHandler?.Invoke(leak);

            added.Add(leak.id);
            while (added.Count > 1024)
            {
                added.RemoveAt(0);
            }
        }
    }

    public class MainModule : TimerModule
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(MainModule));

        public static readonly MainLeakPair pair = new MainLeakPair();
        public static readonly MainStatus status = new MainStatus();
        public static readonly MainCurrent current = new MainCurrent();

        public MainModule()
        {
        }

        public override void OnModuleInitialize()
        {
            base.OnModuleInitialize();
        }

        public override void OnModuleTerminated()
        {
            base.OnModuleTerminated();
        }

        protected override void OnTimer()
        {

            pair.fetch();

            if(pair.Value.Valid)
            {
                status.fetch();
                current.fetch();
            }

        }

        public static void ConfirmAll()
        {
            var leaks = current.GetCurrentLeaks();
            leaks.ForEach(info => Confirm(info));
        }

        public static void Confirm(AjaxLeakInfo info)
        {
            try
            {
                using (Ajax ajax = new Ajax())
                {
                    var url = AnyConfigs.get("APP").get("MainURL").GetOrDefault("http://localhost:8080");

                    AjaxContent content = AjaxContent.Get()
                        .setUrl(url, "client/confirm.do")
                        .AddParameter("id", info.id.ToString());

                    AjaxAnyResult result = ajax.DoPost<AjaxAnyResult>(content);
                    if (result.success)
                    {
                        log.Info("Leak confirmed.");
                    }
                    else
                    {
                        log.Warn(result.message);
                    }
                }

            }
            catch (Exception e)
            {
                log.Error("Exception on confirm warning", e);
            }

        }

    }

}

